/**
 ****************************************************************************
 * Copyright (C) Marcelo F. Ochoa. All rights reserved.                      *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included  with this distribution in *
 * the LICENSE file.                                                         *
 */

package com.prism.utils;

import java.util.Hashtable;

public class Block {
    // holds the locked objects
    private Hashtable blocks = new Hashtable();

    /**
     * Checks if a key is being blocked, and if so blocks this request until notified.
     * If the key is not locked then it becomes locked, so any subsequent calls will block.
     * @param key - The object to be locked.
     * @return boolean - true = a lock was obtained, false = the caller was blocked.
     */
    public synchronized boolean lock(Object key) {
        boolean locked = false;
        if (!this.blocks.containsKey(key)) {
            // flag the key as locked
            //System.out.println( "Locking: " + key);
            this.blocks.put(key, key);
            locked = true;
        } else {
            // block the call
            //System.out.println( "Blocking: " + key);
            try {
                // wait until the block is released by the blocking thread
                while (this.blocks.containsKey(key)) {
                    wait();
                }
            } catch (InterruptedException ie) {
                System.err.println("Wait for '" + key + "' was interrupted");
            }
            this.blocks.put(key, key);
            locked = true;
        }
        //System.out.println(
        //          "Total locks for all pages: " + this.blocks.size());
        return locked;
    } // lock(Object)

    /**
     * All waiting threads are notified.
     * @param key - The object whose lock is to be removed.
     */
    public synchronized void unlock(Object key) {
        // notify all waiting threads if there was a lock on this key
        if (this.blocks.remove(key) != null) {
            //System.out.println( "Releasing lock on: " + key);
            notifyAll();
        }
    } // unlock(Object)
} // end class Block
